/*=============================================================================
// File Name:   drv_dac.c
// Author:      Wood Wang
// Date:        2020/03/14
// Version:     v1.0

=============================================================================*/
/* Includes -----------------------------------------------------------------*/
#include "drv_dac.h"

#include "fsl_dac.h"
#include "fsl_dma.h"
#include "fsl_power.h"

#define DEMO_DAC_BASE          DAC0
#define DEMO_DAC_COUNTER_VALUE 1000U
#define DEMO_DMA_DAC_CHANNEL   22U
#define DEMO_DAC_DATA_REG_ADDR 0x40014000

#define IOCON_PIO_CLKDIV0 0x00u        /*!<@brief IOCONCLKDIV0 */
#define IOCON_PIO_DACMODE_EN 0x010000u /*!<@brief Enables DAC mode */
#define IOCON_PIO_HYS_EN 0x20u         /*!<@brief Enable hysteresis */
#define IOCON_PIO_INV_DI 0x00u         /*!<@brief Input not invert */
#define IOCON_PIO_MODE_INACT 0x00u     /*!<@brief No addition pin function */
#define IOCON_PIO_MODE_PULLUP 0x10u    /*!<@brief Selects pull-up function */
#define IOCON_PIO_OD_DI 0x00u          /*!<@brief Disables Open-drain function */
#define IOCON_PIO_SMODE_BYPASS 0x00u   /*!<@brief Bypass input filter */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static void DMA_Configfuation(void);
dma_transfer_config_t dmaTransferConfigStruct;
/*******************************************************************************
 * Variables
 ******************************************************************************/
dma_handle_t gDmaHandleStruct; /* Handler structure for using DMA. */
const uint32_t g_waveform[] = 
{0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999, 0xAAAA,
0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF, 0xFFFF, 0xEEEE, 0xDDDD, 0xCCCC, 0xBBBB, 0xAAAA,
0x9999, 0x8888, 0x7777, 0x6666, 0x5555, 0x4444, 0x3333, 0x2222, 0x1111, 0x0000};

/*******************************************************************************
 * Code
 ******************************************************************************/
/* Software ISR for DMA transfer done. */
void DEMO_DMA_Callback(dma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
{
    /* Prepare and submit the transfer. */
    DMA_PrepareTransfer(&dmaTransferConfigStruct,       /* To keep the configuration. */
                        (void *)g_waveform,             /* DMA transfer source address. */
                        (void *)DEMO_DAC_DATA_REG_ADDR, /* DMA transfer destination address. */
                        sizeof(uint32_t),               /* DMA transfer destination address width(bytes). */
                        sizeof(g_waveform),             /* DMA transfer bytes to be transferred. */
                        kDMA_MemoryToPeripheral,        /* DMA transfer type. */
                        NULL                            /* nextDesc Chain custom descriptor to transfer. */
    );
    DMA_SubmitTransfer(&gDmaHandleStruct, &dmaTransferConfigStruct);
    DMA_StartTransfer(&gDmaHandleStruct); /* Enable the DMA every time for each transfer. */
}

static void DMA_Configfuation(void)
{
    /* Configure DMA. */
    DMA_Init(DMA0);
    DMA_EnableChannel(DMA0, DEMO_DMA_DAC_CHANNEL);
    DMA_CreateHandle(&gDmaHandleStruct, DMA0, DEMO_DMA_DAC_CHANNEL);
    DMA_SetCallback(&gDmaHandleStruct, DEMO_DMA_Callback, NULL);

    /* Prepare and submit the transfer. */
    DMA_PrepareTransfer(&dmaTransferConfigStruct,       /* To keep the configuration. */
                        (void *)g_waveform,             /* DMA transfer source address. */
                        (void *)DEMO_DAC_DATA_REG_ADDR, /* DMA transfer destination address. */
                        sizeof(uint32_t),               /* DMA transfer destination address width(bytes). */
                        sizeof(g_waveform),             /* DMA transfer bytes to be transferred. */
                        kDMA_MemoryToPeripheral,        /* DMA transfer type. */
                        NULL                            /* nextDesc Chain custom descriptor to transfer. */
    );
    DMA_SubmitTransfer(&gDmaHandleStruct, &dmaTransferConfigStruct);
    DMA_StartTransfer(&gDmaHandleStruct);
}


void drv_dac_gpio_init(void)
{
    dac_config_t dacConfigStruct;

    /* Enables clock for IOCON.: enable */
    CLOCK_EnableClock(kCLOCK_Iocon);
    /* Enables clock for switch matrix.: enable */
    CLOCK_EnableClock(kCLOCK_Swm);

    const uint32_t IOCON_INDEX_PIO0_17_config = (/* No addition pin function */
                                                 IOCON_PIO_MODE_INACT |
                                                 /* Enable hysteresis */
                                                 IOCON_PIO_HYS_EN |
                                                 /* Input not invert */
                                                 IOCON_PIO_INV_DI |
                                                 /* Disables Open-drain function */
                                                 IOCON_PIO_OD_DI |
                                                 /* Bypass input filter */
                                                 IOCON_PIO_SMODE_BYPASS |
                                                 /* IOCONCLKDIV0 */
                                                 IOCON_PIO_CLKDIV0 |
                                                 /* Enables DAC mode */
                                                 IOCON_PIO_DACMODE_EN);
    /* PIO0 PIN17 (coords: 63) is configured as DAC0, DACOUT0. */
    IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_17, IOCON_INDEX_PIO0_17_config);

    /* DACOUT0 connect to P0_17 */
    SWM_SetFixedPinSelect(SWM0, kSWM_DAC_OUT0, true);

    /* Disable clock for switch matrix. */
    CLOCK_DisableClock(kCLOCK_Swm);
    
    /* Power on the DAC0.*/
    POWER_DisablePD(kPDRUNCFG_PD_DAC0); 

    NVIC_EnableIRQ(DMA0_IRQn);
    DMA_Configfuation();
    
    /* Configure the DAC. */
    DAC_GetDefaultConfig(&dacConfigStruct);
    DAC_Init(DEMO_DAC_BASE, &dacConfigStruct);
    /* Enable the DAC DMA. */
    DAC_EnableDMA(DEMO_DAC_BASE, true);
    /* Configure the frequency of DAC DMA. */
    DAC_SetCounterValue(DEMO_DAC_BASE, DEMO_DAC_COUNTER_VALUE);
    DAC_EnableDoubleBuffering(DEMO_DAC_BASE, true);    
}

void DMA0_IRQHandler(void)
{
    DMA_IRQHandle(DMA0);
    SDK_ISR_EXIT_BARRIER;
}
